package com.example.javascaffold.utils;

import com.example.javascaffold.annotation.ExcelInfo;
import com.example.javascaffold.exception.BaseException;
import com.example.javascaffold.exception.ParamException;
import com.example.javascaffold.model.excl.BaseExcel;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;


/**
 * <p>
 *     <strong>Excel工具类</strong>
 * </p>
 * <li>
 * <p>
 *     <strong>示例1: 将数据导出到excel</strong> <br>
 *     需要传入的参数: String filePath(存储的路径和名称)、List<? extends BaseExcel> dataList 传入的数据
 *     Boolean success = ExcelUtils.dataToExcel(filePath, dataList);
 *     结果: success: true 以及 将excel写出到本地
 * </p>
 * </li>
 * @author song
 *
 * @see ExcelInfo
 * @see XSSFWorkbook
 * @see XSSFSheet
 * @see XSSFRow
 * @see XSSFCell
 * @since 11:41 2021/11/19
 **/
public class ExcelUtils {

    private ExcelUtils() {}

    /**
     * <li>
     * <p>
     *     <strong>示例1: 将数据导出到excel</strong> <br>
     *     Boolean success = ExcelUtils.dataToExcel(filePath, dataList);
     *     结果: success: true 以及 将excel写出到本地
     * </p>
     * </li>
    **/
    public static Boolean dataToExcel(String filePath, List<? extends BaseExcel> dataList) throws BaseException {
        if (CheckParamUtils.isNullOrEmpty(filePath)) {
            throw new ParamException("写出excel的路径fileName不能为空");
        }
        // 获取字段注解上的排序
        Object object = dataList.get(0);
        // 拿到定义的字段
        Field[] fields = object.getClass().getDeclaredFields();
        // 遍历字段 通过注解拿到 字段的相关信息
        // 这里通过排序 给字段排序
        for (int i = 0; i < fields.length; i ++) {
            for (int j = i + 1; j < fields.length; j ++) {
                Field fi = fields[i];
                Field fj = fields[j];
                ExcelInfo infoI = fi.getAnnotation(ExcelInfo.class);
                ExcelInfo infoJ = fj.getAnnotation(ExcelInfo.class);
                // 顺序值
                if (infoI.number() > infoJ.number()) {
                    // 交换位置
                    Field tempField = fields[i];
                    fields[i] = fields[j];
                    fields[j] = tempField;
                }
            }
        }

        // 排序之后 字段已经按照理想状况排列
        // 下面开始写出
        // 初始化Excel
        XSSFWorkbook workBook = new XSSFWorkbook();
        XSSFSheet sheet = workBook.createSheet("sheet");
        // 写标题
        XSSFRow row = sheet.createRow(0);
        for(int i = 0; i < fields.length; i ++){
            // 通过注解获取标题
            Field field = fields[i];
            ExcelInfo info = field.getAnnotation(ExcelInfo.class);
            XSSFCell cell = row.createCell(i);
            cell.setCellValue(info.title());
        }

        // 将dataList的数据写入到每一行
        for (int i = 0; i < dataList.size(); i ++) {
            // dataList每个对象为一行
            Object eachObject = dataList.get(i);
            XSSFRow objectRow = sheet.createRow(i + 1);
            // 定义的字段
            for (int j = 0; j < fields.length; j ++) {
                Field field = fields[j];
                // 每个字段为一列
                XSSFCell cells = objectRow.createCell(j);
                try {
                    // 反射执行 获取值
                    Method method = eachObject.getClass().getMethod("get" + toFirstUp(field.getName()));
                    Object cellValue = method.invoke(eachObject);
                    cells.setCellValue(null == cellValue ? "" : cellValue.toString());
                } catch (Exception e) {
                    cells.setCellValue("");
                    e.printStackTrace();
                }
            }
        }

        // 保存写出
        try {
            File file = new File(filePath);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            workBook.write(fileOutputStream);
            workBook.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    
    /**
     * 首字母大写
     * @author song
     * @date 13:44 2021/11/23
    **/
    private static String toFirstUp(String str) {
        char[] cs = str.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

}
